<?php

class Helper_Render
{
	/**
	 * @param array $rows
	 * @return array with structure.
	 */
	public function prepareElements($rows)
	{

		$areas = array();
		$maps = array();
		$result = array();

		foreach ($rows as $row)
		{
			if (0 == $row['pid'])
			{
				$areas[$row['id']] = $row['area'];
			}
			$maps[$row['id']] = $this -> prepareElement($row);
		}

		unset($rows);

		$nest = array(
				'block' => array('list', ),
				'list' => array('list', ),
		);

		/**
		 * layout contain area
		 * area contain /list/block
		 * list contain list/block
		 * block contain block
		 */
		foreach ($nest as $type => $parentTypes)
		{
			foreach ($parentTypes as $parentType)
			{
				foreach ($maps as $index => $row)
				{
					if ($type == $row['type'])
					{
						$pid = $row['pid'];
						if (isset($maps[$pid]) && isset($maps[$pid]['type']) && $parentType == $maps[$pid]['type'])
						{
							$maps[$pid]['children'][] = $row;
							unset($maps[$index]);
							// remote from maps.
						}
					}
				}
			}
		}

		foreach ($areas as $id => $area)
		{
			$result[$area][] = $maps[$id];
		}
		// unset all maps.
		unset($maps);

		return $result;
	}

	public function prepareElement($row)
	{
		if (!isset($row['children']))
		{
			$row['children'] = array();
		}
		return $row;
	}

	public function getAvailableActionList($actionId)
	{
		$result = array($actionId);
		$arr = preg_split('#\W#', $actionId);
		$m_first = array_shift($arr);
		$m_mid = $arr[0];
		$m_end = array_pop($arr);
		$m_remain = implode('.', $arr);

		$result[] = sprintf('%s@%s', $m_first, $m_remain);
		$result[] = sprintf('%s@%s', $m_first, $m_mid);
		$result[] = sprintf('core@%s', $m_remain);
		$result[] = sprintf('core@%s', $m_mid);
		$result[] = 'core@';
		$result = array_unique($result);
		return $result;
	}

	public function loadLayout($name, $actionId, $siteId)
	{
		$key = Nuo::getHelper('@string') -> createHash($name, $actionId, $siteId);

		$cache = Nuo::getHelper('@cache') -> getCache('core');

		if (false !== ($result = $cache -> load($key)))
		{
			return $result;
		}

		$actionList = $this -> getAvailableActionList($actionId);

		$table = Nuo::getTable('core@render.layout');

		// echo sprintf("get layout match [%s]", implode(';', $actionList));

		$select = $table -> select() -> where('layout_name=?', $name) -> where('action_id IN (?)', $actionList) -> order('action_id DESC');

		$layout = $table -> fetchRow($select);

		$id = intval($layout -> layout_id);

		$table = Nuo::getTable('core@render.element');

		$select = $table -> select() -> where('layout_id=?', $id) -> order('priority ASC');

		$areas = $this -> prepareElements($table -> fetchAll($select) -> toArray());

		$result = array(
				$layout -> toArray(),
				$areas
		);

		$cache -> save($result, $key);

		return $result;
	}

	/**
	 * $ele = array('id'=>int,
	 * 'action_id'=>'string','params'=>string,'children'=>array())
	 * @param array $ele
	 * @param string $actionId
	 * @return string
	 */
	public function renderElement($element = null)
	{
		$params = array();
		$type = $element['type'];
		$spec = $element['spec'];

		if ('list' == $type)
		{
			/**
			 * check spec to render.
			 */
		}
		else
		if ('block' == $type)
		{
			$params = array();

			$request = new Request();

			$html = $request -> setParam($params) -> setActionId($element['name']) -> dispatch();

			unset($request);

			return sprintf("<div>%s</div>", $html);
		}

	}

	/**
	 * $eles = array[array('id'=>int,
	 * 'action_id'=>'string','params'=>string,'children'=>array())]
	 * @param array $blocks
	 *
	 */
	public function renderElements($elements)
	{
		$xhtml = array();
		if (is_array($elements))
		{
			foreach ($elements as $element)
			{

				$xhtml[] = $this -> renderElement($element, null);

			}

		}
		return implode(PHP_EOL, $xhtml);
	}

	/**
	 * check if accept empty content.
	 */
	public function renderArea($allAreas, $areaName, $acceptEmpty = false)
	{
		$html = '';
		$area = isset($allAreas[$areaName]) ? $allAreas[$areaName] : array();

		if (!empty($area))
		{
			$html = $this -> renderElements($area);
		}

		if ($acceptEmpty == false && '' == $html)
		{
			return;
		}

		return sprintf('<div class="layout-area-%s">%s</div>', $areaName, $html);
	}

	/**
	 * @param string $region
	 * @param array $areas
	 * @return string
	 */
	public function renderLayout($name, $actionId = null, $siteId = null)
	{

		/**
		 * load section layout
		 */
		list($layout, $areas) = $this -> loadLayout($name, $actionId, $siteId);

		if (null == $layout)
		{
			return '';
		}

		$script = 'layout/areas/' . $layout['layout_script'] . '.tpl';

		return View::render(array(
				'parser' => $this,
				'layout' => $name,
				'areas' => $areas,
				'actionId' => $actionId,
				'siteId' => $siteId,
		), $script);
	}

	/**
	 * process render layout
	 * @param string $page
	 * @param string $actionId
	 * @param int $siteId
	 * @return string
	 */
	protected function _renderPage($page = null, $actionId = null, $siteId = null)
	{
		if (null == $siteId)
		{
			$siteId = Nuo::get('siteId');
		}

		if (null == $actionId)
		{
			$actionId = Nuo::getRequest() -> getActionId();
		}

		if (null == $page)
		{
			$page = 'default';
		}

		$script = 'layout/pages/' . $page . '.tpl';

		return View::render(array(
				'page' => $page,
				'actionId' => $actionId,
				'siteId' => $siteId,
				'parser' => $this
		), $script);
	}

	public function renderPage($page, $actionId = null, $siteId = null)
	{

		Nuo::fireEvent('onRenderPageStartup');

		$content = $this -> _renderPage($page, $actionId);

		Nuo::fireEvent('onRenderPageShutdown');

		$head = Nuo::getHelper('@head');

		return '<html><head>' . $head . '</head><body>' . $content . '</body>' . '</html>';
	}

}
